/**Copyright (c) 2010, Isidoro Trevino de la Garza (chololo@gmail.com)
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:
(1)Redistributions of source code must retain the above copyright notice, this list 
of conditions and the following disclaimer. 
(2)Redistributions in binary form must reproduce the above copyright notice, this 
list of conditions and the following disclaimer in the documentation and/or other 
materials provided with the distribution. 
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
DAMAGE.
*/
package org.citsa.ofbiz.parser

import java.io.File;
import org.citsa.configuration.ConfigurationManager 
import org.citsa.ofbiz.beans.EntityResource 
import org.citsa.ofbiz.beans.entity.Alias 
import org.citsa.ofbiz.beans.entity.AliasAll 
import org.citsa.ofbiz.beans.entity.Entity 
import org.citsa.ofbiz.beans.entity.ExtendEntity 
import org.citsa.ofbiz.beans.entity.MemberEntity 
import org.citsa.ofbiz.beans.entity.Relation 
import org.citsa.ofbiz.beans.entity.ViewEntity 
import org.citsa.ofbiz.beans.entity.ViewLink 

class EntityParser {

	ConfigurationManager config = ConfigurationManager.instance()
	
	def completeRelationships(){
		FileComponentRegistry registry = FileComponentRegistry.instance()
		
		completeViewEntityRelationShips(registry.entities,registry.viewEntities)
		completeEntityRelationShips(registry.entities,registry.extendEntities,registry.viewEntities)
		
	}
	
	def completeEntityRelationShips(Map<String,Entity> entities,Map<String,Entity> extendEntities,Map<String,Entity> viewEntities){
		def relEntity
		extendEntities.each{
			key,ExtendEntity entity ->
			relEntity = findEntity(entity.entityName,entities, viewEntities,true)
			if(!relEntity){
				println "WARN: [ExtendEntity - relEntity] Didn't find a matching entity for ${entity.entityName} (module: ${entity.parent.module})"
			}
			else{
				relEntity.extendedEntities << entity
				entity.relatedEntity = relEntity				
			}
			entity.relations.each{
				Relation relation ->
				relEntity = entities[relation.relEntityName]
                if(!relEntity){
					println "WARN: [ExtendEntity - relation] Didn't find a matching entity for ${relation.relEntityName} declared in ${entity.entityName} (module: ${entity.parent.module})"
				}
				else{
					relation.relatedEntity = relEntity
					relation.mapEntity(relEntity)
				} 
			}
			
		}
		entities.each{
			key,Entity entity ->
			entity.relations.each{
				Relation relation ->
				relEntity = findEntity(relation.relEntityName,entities, viewEntities)
                if(!relEntity){
					println "WARN: [Entity - relation] Didn't find a matching entity for ${relation.relEntityName} declared in ${entity.entityName} (module: ${entity.parent.module})"
				}
				else{
					relation.relatedEntity = relEntity
					relation.mapEntity(relEntity)
				} 
			}
		}
	}
	
	def completeViewEntityRelationShips(Map<String,Entity> entities,Map<String,Entity> viewEntities){
		def entity
		
		viewEntities.each{
			key,ViewEntity viewEntity ->
			//Populate member entity relations
			def aliasMap = [:]
			viewEntity.memberEntities.each{
				MemberEntity memberEntity ->
			
				entity = findEntity(memberEntity.entityName,entities,viewEntities)
				if(!entity){
						println "WARN: [ViewEntity - MemberEntity] Didn't find a matching entity for ${memberEntity.entityName} declared in ${viewEntity.entityName} (module: ${viewEntity.parent.module})"
				}
				else{
					memberEntity.relatedEntity = entity
				}
				aliasMap[memberEntity.entityAlias] = memberEntity.entityName
			}
			//Populate aliases
			viewEntity.aliases.each{
				Alias alias ->
				entity = findEntity(aliasMap[alias.entityAlias],entities,viewEntities)
                if(!entity){
  					println "WARN: [ViewEntity - Alias] Didn't find a matching entity for ${alias.entityAlias} declared in ${viewEntity.entityName} (module: ${viewEntity.parent.module})"
  				}
  				else{
  					alias.relatedEntity = entity					
  				}
			}
			//Populate alias all
			viewEntity.aliasesall.each{
				AliasAll alias ->
				  entity = findEntity(aliasMap[alias.entityAlias],entities,viewEntities)
	              if(!entity){
						println "WARN: [ViewEntity - AliasAll] Didn't find a matching entity for ${alias.entityAlias} declared in ${viewEntity.entityName} (module: ${viewEntity.parent.module})"
					}
					else{
						alias.relatedEntity = entity					
					}
			}
			//Populate view links
			viewEntity.viewLinks.each{
				ViewLink link ->
				
				  entity = findEntity(aliasMap[link.entityAlias],entities,viewEntities)
                  if(!entity){
						println "WARN: [ViewEntity - ViewLink] Didn't find a matching entity for ${link.entityAlias} declared in ${viewEntity.entityName} (module: ${viewEntity.parent.module})"
					}
					else{
						link.relatedEntity= entity
						link.mapEntity(entity)
					}
				  entity = findEntity(aliasMap[link.relEntityAlias],entities,viewEntities)
				
              if(!entity){
					println "WARN: [ViewEntity - ViewLink.relEntityAlias] Didn't find a matching entity for ${link.relEntityAlias} declared in ${viewEntity.entityName} (module: ${viewEntity.parent.module})"
				}
				else{
					link.relatedLinkEntity= entity
				}                
			}
			//Populate relations
			viewEntity.relations.each{
				Relation relation ->
				entity = findEntity(relation.relEntityName,entities,viewEntities)
                if(!entity){
  					println "WARN: [ViewEntity - Relation] Didn't find a matching entity for ${relation.relEntityName} declared in ${viewEntity.entityName} (module: ${viewEntity.parent.module})"
  				}
  				else{
  					relation.relatedEntity = entity
  					relation.mapEntity(entity)
  				}                  
			}
		}
	}
	
	def findEntity(String entityName,Map entities, Map viewEntities,boolean extended=false){
		def entity = entities[entityName]
		if(!entity){
			// println "Didn't find --${entityName}-- looking in ViewEntities" DEBUG
			if(extended){
				println "EXTENDED VIEW ENTITY: ${entityName}"
			}
			entity = viewEntities[entityName]
		}
		return entity		
	}
	
	def updateRegistry(EntityResource component){
		FileComponentRegistry registry = FileComponentRegistry.instance()
		component.entities.each{
			entity ->
			registry.entities[entity.entityName] = entity
		}
		component.viewEntities.each{
			entity ->
			registry.viewEntities[entity.entityName] = entity
		}
		component.extendEntities.each{
			entity ->
			registry.extendEntities[entity.entityName+"_"+entity.parent] = entity
		}
	}
	
	def parseService(EntityResource component){
		File file = config.getServicePath(component)
		if(file.exists()){
			def document = new XmlParser().parse(file)
			parseEntities(component,document)
			parseViewEntities(component,document)
			parseExtendEntities(component,document)
			populateGeneralProperties component, document
		}
	}
	
	def parseEntities(EntityResource component, def xml){
		def entities = xml.'entity'
		entities.each{
			ent ->
			Entity entity = new Entity()
			entity.populateAttributes(ent)
			entity.parent= component
			component.entities << entity			
		}
	}
	def parseViewEntities(EntityResource component, def xml){
		def entities = xml.'view-entity'
		entities.each{
			ent ->
			ViewEntity entity = new ViewEntity()
			entity.populateAttributes(ent)
			entity.parent= component
			component.viewEntities << entity			
		}
	}
	def parseExtendEntities(EntityResource component, def xml){
		def entities = xml.'extend-entity'
		entities.each{
			ent ->
			ExtendEntity entity = new ExtendEntity()
			entity.populateAttributes(ent)
			entity.parent= component
			component.extendEntities << entity			
		}
	}
	
	def populateGeneralProperties(EntityResource component, def xml){
		component.title=xml.'title'?.text()?:""
		component.description=xml.'description'?.text()?:""
		component.copyright=xml.'copyright'?.text()?:""
		component.author=xml.'author'?.text()?:""
		component.version=xml.'version'?.text()?:""
	}
	
}
